////////////////////////////////////////////////////////////////////////////////

#include "server_session.h"

////////////////////////////////////////////////////////////////////////////////

#include "mutex.h"
#include "timer.h"

////////////////////////////////////////////////////////////////////////////////


ServerSession::ServerSession( ClientPackets& _recvQueue,
                              ServerPackets& _sendQueue,
                              Mutex& _sendQueueMutex,
                              Mutex& _recvQueueMutex,
                              boost::asio::io_service& _io_service )
: m_SendSocket(_io_service),
  m_RecvSocket(_io_service),
  m_RecvQueue(_recvQueue),
  m_SendQueue(_sendQueue),
  m_RecvQueueMutex(_recvQueueMutex),
  m_SendQueueMutex(_sendQueueMutex),
  m_SendThread(NULL),
  m_RecvThread(NULL)
{
}


////////////////////////////////////////////////////////////////////////////////


ServerSession::~ServerSession()
{
    // Stop sending
    if (m_SendThread)
    {
        delete m_SendThread;
    }

    // Stop receiving
    if (m_RecvThread)
    {
        delete m_RecvThread;
    }
}


////////////////////////////////////////////////////////////////////////////////


void ServerSession::Send()
{
    bool continueSending = true;
    while (continueSending)
    {
        // Lock collection
        m_SendQueueMutex.Lock();

        // Send all
        while( !m_SendQueue.empty() && continueSending )
        {
            ServerPacket& packet = m_SendQueue.back();

            // Send packet
            boost::system::error_code ignored_error;
            boost::asio::write(m_SendSocket, boost::asio::buffer( packet.ToStr() ),
                boost::asio::transfer_all(), ignored_error);

            m_SendQueue.pop();
        }

        // Unlock
        m_SendQueueMutex.Unlock();

        // Be kind to CPU
        Timer::Delay(1);
    }
}


////////////////////////////////////////////////////////////////////////////////


void ServerSession::Receive()
{
    bool continueReceiving = true;
    while (continueReceiving)
    {
        boost::array<char, 128> buf;

        boost::system::error_code error;

        size_t len = m_RecvSocket.read_some(boost::asio::buffer(buf), error);

        if (error == boost::asio::error::eof)
            break; // Connection closed cleanly by peer.
        else if (error)
            throw boost::system::system_error(error); // Some other error.

        ClientPacket packet;
        packet.FromStr( buf.data() );

        // Lock recv collection
        m_RecvQueueMutex.Lock();
        m_RecvQueue.push(packet);

        // Unlock
        m_RecvQueueMutex.Unlock();

        // Be kind to CPU
        Timer::Delay(1);
    }
}


////////////////////////////////////////////////////////////////////////////////


void ServerSession::Start()
{
    if (!m_SendThread)
    {
        // Start thread for sending
        m_SendThread = new Thread(&ServerSession::Send, this);
    }
        

    if (!m_RecvThread)
    {
        // Receive in this thread
        m_RecvThread = new Thread(&ServerSession::Receive, this);
    }
}


////////////////////////////////////////////////////////////////////////////////


tcp::socket& ServerSession::GetSendSocket()
{
    return m_SendSocket;
}

////////////////////////////////////////////////////////////////////////////////


tcp::socket& ServerSession::GetRecvSocket()
{
    return m_RecvSocket;
}


////////////////////////////////////////////////////////////////////////////////
